﻿using System;
using System.Windows.Controls;
using System.Net;
using System.Xml;
using System.Windows;
using System.Xml.Serialization;
using System.IO;

namespace Charting
{
    public partial class EmailControl : UserControl
    {
        public EmailControl(string attachmentPath)
        {
            InitializeComponent();

            //Load Data
            ChartData actualChartData = new ChartData
            {
                Title = "Actual",
                Range = 240000,
                RangeFormatString = "$#,##0"
            };

            ChartData projectedChartData = new ChartData
            {
                Title = "Projected",
                Range = 240000,
                RangeFormatString = "$#,##0"
            };

            LoadXMLData(attachmentPath, actualChartData, projectedChartData);

            this.ActualChart.SetData(actualChartData);
            this.ProjectedChart.SetData(projectedChartData);
        }

#region "Private Data Load Methods"
        private void LoadXMLData(string attachPath, ChartData actualData, ChartData forecastData)
        {
            //System.IO.FileStream fs = new System.IO.FileStream(attachPath, System.IO.FileMode.Open);
            System.Xml.XmlNode xDocumentNode;
            System.Xml.XmlDocument xDoc = new System.Xml.XmlDocument();
            xDoc.Load(attachPath);
            // Within the document, the first "0" node is the header, 1 is the body.  
            // Within this the next node is the common data - "General Info".  
            // The final node is the sales and forecast data (combined)
            xDocumentNode = xDoc.ChildNodes[1].ChildNodes[0];
            //<TerritoryName></TerritoryName>
            labelSalesTerritory.Content = "Territory: \t\t" + xDocumentNode.ChildNodes[1].InnerText;
            //<TerritoryID></TerritoryID>
            //<Region></Region>
            labelSalesRegion.Content = "Region: \t\t" + xDocumentNode.ChildNodes[3].InnerText;
            //<SalesManager></SalesManager>
            labelSalesManager.Content = "Sales Manager: \t" + xDocumentNode.ChildNodes[4].InnerText;
            //<SalesPerson></SalesPerson>
            labelSalesPerson.Content = "Sales Person: \t" + xDocumentNode.ChildNodes[5].InnerText;
            //<SalesPersonID></SalesPersonID>
            //<ReportDate></ReportDate>
            string sDt = xDocumentNode.ChildNodes[7].InnerText;
            DateTime dt = DateTime.Parse(sDt);
            labelSubmitDate.Content = "Submission Date: \t" + dt.ToLongDateString();
            //<SpreadSheetUrl></SpreadSheetUrl>
            ExcelLink.NavigateUri = new System.Uri(xDocumentNode.ChildNodes[8].InnerText);
            //<ReportUrl></ReportUrl>
            WordLink.NavigateUri = new System.Uri(xDocumentNode.ChildNodes[9].InnerText);
            //<Comments />
            textBoxSubmitComments.Text = xDocumentNode.ChildNodes[10].InnerText;

            string companyName;
            string [] forecastColumnNames = new string[4];
            string [] actualColumnNames = new string[4];
            // Get the sales and forecast data...
            xDocumentNode = xDoc.ChildNodes[1].ChildNodes[1];

            System.Xml.XmlNode xFirstCustomer = xDoc.ChildNodes[1].ChildNodes[1].FirstChild;

            //// But first define the columns
            //// Within each company is where we'll find the years... the challenge is that the
            //// data could span 2 or 3 years.  The data is currently coming out with the most recent first.
            //// need to add columns based on the year and quarter info provided, so need to count years
            //// backward... and quarters forward (projected year(s) 1, quarters from 0 to 3, actual year(s) quarters 0 to 3
            //// plus I don't want to reset these for each company...

            int pivotYear = dt.Year;
            int pivotMonth = dt.Month;
            int pivotQuarter;
            switch (pivotMonth)
            {
                case 1:
                case 2:
                case 3:
                    pivotQuarter = 3;
                    actualData.Columns.Add("FY" + (pivotYear - 1).ToString().Substring(2) + "Q4");
                    actualData.Columns.Add("FY" + pivotYear.ToString().Substring(2) + "Q1");
                    actualData.Columns.Add("FY" + pivotYear.ToString().Substring(2) + "Q2");
                    actualData.Columns.Add("FY" + pivotYear.ToString().Substring(2) + "Q3");

                    forecastData.Columns.Add("FY" + pivotYear.ToString().Substring(2) + "Q4");
                    forecastData.Columns.Add("FY" + (pivotYear + 1).ToString().Substring(2) + "Q1");
                    forecastData.Columns.Add("FY" + (pivotYear + 1).ToString().Substring(2) + "Q2");
                    forecastData.Columns.Add("FY" + (pivotYear + 1).ToString().Substring(2) + "Q3");
                    break;
                case 4:
                case 5:
                case 6:
                    pivotQuarter = 4;
                    actualData.Columns.Add("FY" + pivotYear.ToString().Substring(2) + "Q1");
                    actualData.Columns.Add("FY" + pivotYear.ToString().Substring(2) + "Q2");
                    actualData.Columns.Add("FY" + pivotYear.ToString().Substring(2) + "Q3");
                    actualData.Columns.Add("FY" + pivotYear.ToString().Substring(2) + "Q4");

                    forecastData.Columns.Add("FY" + (pivotYear + 1).ToString().Substring(2) + "Q1");
                    forecastData.Columns.Add("FY" + (pivotYear + 1).ToString().Substring(2) + "Q2");
                    forecastData.Columns.Add("FY" + (pivotYear + 1).ToString().Substring(2) + "Q3");
                    forecastData.Columns.Add("FY" + (pivotYear + 1).ToString().Substring(2) + "Q4");
                    break;
                case 7:
                case 8:
                case 9:
                    pivotQuarter = 1;
                    pivotYear += 1;
                    actualData.Columns.Add("FY" + (pivotYear - 1).ToString().Substring(2) + "Q2");
                    actualData.Columns.Add("FY" + (pivotYear - 1).ToString().Substring(2) + "Q3");
                    actualData.Columns.Add("FY" + (pivotYear - 1).ToString().Substring(2) + "Q4");
                    actualData.Columns.Add("FY" + pivotYear.ToString().Substring(2) + "Q1");

                    forecastData.Columns.Add("FY" + pivotYear.ToString().Substring(2) + "Q2");
                    forecastData.Columns.Add("FY" + pivotYear.ToString().Substring(2) + "Q3");
                    forecastData.Columns.Add("FY" + pivotYear.ToString().Substring(2) + "Q4");
                    forecastData.Columns.Add("FY" + (pivotYear + 1).ToString().Substring(2) + "Q1");
                    break;
                case 10:
                case 11:
                case 12:
                    pivotQuarter = 2;
                    pivotYear += 1;
                    actualData.Columns.Add("FY" + (pivotYear - 1).ToString().Substring(2) + "Q3");
                    actualData.Columns.Add("FY" + (pivotYear - 1).ToString().Substring(2) + "Q4");
                    actualData.Columns.Add("FY" + pivotYear.ToString().Substring(2) + "Q1");
                    actualData.Columns.Add("FY" + pivotYear.ToString().Substring(2) + "Q2");

                    forecastData.Columns.Add("FY" + pivotYear.ToString().Substring(2) + "Q3");
                    forecastData.Columns.Add("FY" + pivotYear.ToString().Substring(2) + "Q4");
                    forecastData.Columns.Add("FY" + (pivotYear + 1).ToString().Substring(2) + "Q1");
                    forecastData.Columns.Add("FY" + (pivotYear + 1).ToString().Substring(2) + "Q2");
                    break;
                default:
                    pivotQuarter = 0;
                    break;
            }

            foreach (System.Xml.XmlNode xChild in xDocumentNode)
            {
                // In the sales node.  It should have 5 children (which can be looped)
                // which represent the customers... get the customer name and data for each customer.
                companyName = xChild.FirstChild.InnerText;
                actualData.Rows.Add(companyName);
                forecastData.Rows.Add(companyName);
                PopulateZeros(companyName, actualData, forecastData, pivotYear, pivotQuarter);

                //Now process the data for this company
                // Within each customer need to jump past the name and id and get to the years.
                string strYear;
                string strQuarter;
                string rawValue;
                double dValue;
                for (int i = 2; i < xChild.ChildNodes.Count; i++)
                {
                    strYear = xChild.ChildNodes[i].FirstChild.InnerText;
                    for (int j = 0; j < xChild.ChildNodes[i].ChildNodes[1].ChildNodes.Count; j++)
                    {
                        strQuarter = xChild.ChildNodes[i].ChildNodes[1].ChildNodes[j].FirstChild.InnerText;
                        // Determine whether this is current or future
                        if (IsForecast(pivotYear, pivotQuarter, strYear, strQuarter))
                        {
                            rawValue = xChild.ChildNodes[i].ChildNodes[1].ChildNodes[j].ChildNodes[2].InnerText;
                            rawValue = rawValue.Replace("$", "");
                            rawValue = rawValue.Replace(",", "");
                            if (double.TryParse(rawValue, out dValue))
                                forecastData.SetValue(companyName, "FY" + strYear.Substring(2) + "Q" + strQuarter, dValue);
                        }
                        else
                        {
                            rawValue = xChild.ChildNodes[i].ChildNodes[1].ChildNodes[j].ChildNodes[1].InnerText;
                            rawValue = rawValue.Replace("$", "");
                            rawValue = rawValue.Replace(",", "");
                            if (double.TryParse(rawValue, out dValue))
                                actualData.SetValue(companyName, "FY" + strYear.Substring(2) + "Q" + strQuarter, dValue);
                        }
                    }
                }
            }
        }

        /// <summary>
        /// Ensure that each column has a value
        /// </summary>
        /// <param name="companyName"></param>
        /// <param name="actualData"></param>
        /// <param name="ForecastData"></param>
        /// <param name="pivotYear"></param>
        /// <param name="pivotQuarter"></param>
        /// <remarks>The XML used to populate the charts does not contain zeros for 
        /// null values as a result the code needs to ensure that there is at least
        /// a starting 0 value for each column so the base of that column will appear
        /// in the display.  This has to be done on a per company basis.</remarks>
        private void PopulateZeros(string companyName, ChartData actualData, ChartData forecastData, int pivotYear, int pivotQuarter)
        {
            switch (pivotQuarter)
            {
                case 3:
                    actualData.SetValue(companyName, "FY" + (pivotYear - 1).ToString().Substring(2) + "Q4", 0.0);
                    actualData.SetValue(companyName, "FY" + pivotYear.ToString().Substring(2) + "Q1", 0.0);
                    actualData.SetValue(companyName, "FY" + pivotYear.ToString().Substring(2) + "Q2", 0.0);
                    actualData.SetValue(companyName,"FY" + pivotYear.ToString().Substring(2) + "Q3", 0.0);

                    forecastData.SetValue(companyName, "FY" + pivotYear.ToString().Substring(2) + "Q4", 0.0);
                    forecastData.SetValue(companyName, "FY" + (pivotYear + 1).ToString().Substring(2) + "Q1", 0.0);
                    forecastData.SetValue(companyName, "FY" + (pivotYear + 1).ToString().Substring(2) + "Q2", 0.0);
                    forecastData.SetValue(companyName, "FY" + (pivotYear + 1).ToString().Substring(2) + "Q3", 0.0);
                    break;
                case 4:
                    actualData.SetValue(companyName,"FY" + pivotYear.ToString().Substring(2) + "Q1", 0.0);
                    actualData.SetValue(companyName,"FY" + pivotYear.ToString().Substring(2) + "Q2", 0.0);
                    actualData.SetValue(companyName,"FY" + pivotYear.ToString().Substring(2) + "Q3", 0.0);
                    actualData.SetValue(companyName,"FY" + pivotYear.ToString().Substring(2) + "Q4", 0.0);

                    forecastData.SetValue(companyName, "FY" + (pivotYear + 1).ToString().Substring(2) + "Q1", 0.0);
                    forecastData.SetValue(companyName, "FY" + (pivotYear + 1).ToString().Substring(2) + "Q2", 0.0);
                    forecastData.SetValue(companyName, "FY" + (pivotYear + 1).ToString().Substring(2) + "Q3", 0.0);
                    forecastData.SetValue(companyName, "FY" + (pivotYear + 1).ToString().Substring(2) + "Q4", 0.0);
                    break;
                case 1:
                    actualData.SetValue(companyName,"FY" + (pivotYear - 1).ToString().Substring(2) + "Q2", 0.0);
                    actualData.SetValue(companyName,"FY" + (pivotYear - 1).ToString().Substring(2) + "Q3", 0.0);
                    actualData.SetValue(companyName,"FY" + (pivotYear - 1).ToString().Substring(2) + "Q4", 0.0);
                    actualData.SetValue(companyName,"FY" + pivotYear.ToString().Substring(2) + "Q1", 0.0);

                    forecastData.SetValue(companyName, "FY" + pivotYear.ToString().Substring(2) + "Q2", 0.0);
                    forecastData.SetValue(companyName, "FY" + pivotYear.ToString().Substring(2) + "Q3", 0.0);
                    forecastData.SetValue(companyName, "FY" + pivotYear.ToString().Substring(2) + "Q4", 0.0);
                    forecastData.SetValue(companyName, "FY" + (pivotYear + 1).ToString().Substring(2) + "Q1", 0.0);
                    break;
                case 2:
                    actualData.SetValue(companyName,"FY" + (pivotYear - 1).ToString().Substring(2) + "Q3", 0.0);
                    actualData.SetValue(companyName,"FY" + (pivotYear - 1).ToString().Substring(2) + "Q4", 0.0);
                    actualData.SetValue(companyName,"FY" + pivotYear.ToString().Substring(2) + "Q1", 0.0);
                    actualData.SetValue(companyName,"FY" + pivotYear.ToString().Substring(2) + "Q2", 0.0);

                    forecastData.SetValue(companyName, "FY" + pivotYear.ToString().Substring(2) + "Q3", 0.0);
                    forecastData.SetValue(companyName, "FY" + pivotYear.ToString().Substring(2) + "Q4", 0.0);
                    forecastData.SetValue(companyName, "FY" + (pivotYear + 1).ToString().Substring(2) + "Q1", 0.0);
                    forecastData.SetValue(companyName, "FY" + (pivotYear + 1).ToString().Substring(2) + "Q2", 0.0);
                    break;
                default:
                    break;
            }
        }

        /// <summary>
        /// Determine if a given year and quarter should be for actual or forecast data
        /// </summary>
        /// <param name="pivotYear">The year of the report</param>
        /// <param name="pivotQuarter">The quarter in which the report is being run.</param>
        /// <param name="year">The year to be checked</param>
        /// <param name="quarter">The quarter to be checked.</param>
        /// <returns></returns>
        private bool IsForecast(int pivotYear, int pivotQuarter, string year, string quarter)
        {
            // if the pivot year is less then the data then so is the current date making this a forecast
            if (pivotYear < Convert.ToInt32(year))
                return true;
            // if the pivot year is greater then the data, then the data is in the past making this an actual
            if (pivotYear > Convert.ToInt32(year))
                return false;
            // at this point the years are equal... so is the pivot month less?
            if (pivotQuarter < Convert.ToInt32(quarter))
                return true;
            return false;
        }
#endregion

#region "Link Handlers"
        public void ExcelLink_Click(System.Object sender, System.EventArgs e)
        {
            System.Diagnostics.Process.Start(ExcelLink.NavigateUri.ToString());
        }

        public void WordLink_Click(System.Object sender, System.EventArgs e)
        {
            System.Diagnostics.Process.Start(WordLink.NavigateUri.ToString());
        }

        public void SiteLink_Click(System.Object sender, System.EventArgs e)
        {
            System.Diagnostics.Process.Start(SiteLink.NavigateUri.ToString());
        }
#endregion

#region "Button Handlers"
        public void ButtonAccept_Click(System.Object sender, System.EventArgs e)
        {
            WorkflowApprovalData workflowData = new WorkflowApprovalData();
            workflowData.instructions = textBoxReviewComments.Text;
            workflowData.isApproved = "true";
            workflowData.isRejected = "false";
            if (UpdateWorkflow(workflowData)) 
            System.Windows.Forms.MessageBox.Show("Accepted status submitted.");
        }
        public void ButtonChange_Click(System.Object sender, System.EventArgs e)
        {
            WorkflowApprovalData workflowData = new WorkflowApprovalData();
            workflowData.instructions = textBoxReviewComments.Text;
            workflowData.isApproved = "false";
            workflowData.isRejected = "false";
            if (UpdateWorkflow(workflowData))
            System.Windows.Forms.MessageBox.Show("Change status submitted.");
        }
        public void ButtonReject_Click(System.Object sender, System.EventArgs e)
        {
            WorkflowApprovalData workflowData = new WorkflowApprovalData();
            workflowData.instructions = textBoxReviewComments.Text;
            workflowData.isApproved = "false";
            workflowData.isRejected = "true";
            if (UpdateWorkflow(workflowData))
            System.Windows.Forms.MessageBox.Show("Rejected status submitted.");
        }
#endregion

        private bool UpdateWorkflow(WorkflowApprovalData workflowData)
        {
            WorkflowSoapProxy workflowWebSvc =
                new WorkflowSoapProxy("http://moss.litwareinc.com/docs/sales reports/");
            workflowWebSvc.Credentials = (NetworkCredential)CredentialCache.DefaultCredentials;
            try
            {
                XmlNode itemWorkflowData = workflowWebSvc.GetWorkflowDataForItem(ExcelLink.NavigateUri.ToString());
                XmlDocument workflowInfo = new XmlDocument();
                workflowInfo.LoadXml("<WorkflowInformation>" + itemWorkflowData.InnerXml + "</WorkflowInformation>");
                XmlNamespaceManager nsMgr = new XmlNamespaceManager(new NameTable());
                nsMgr.AddNamespace("spWf", "http://schemas.microsoft.com/sharepoint/soap/workflow/");
                nsMgr.AddNamespace("z", "#RowsetSchema");
                XmlNode documentApprovalWorkflowTemplate =
                    workflowInfo.SelectSingleNode("//spWf:TemplateData/spWf:WorkflowTemplates/spWf:WorkflowTemplate[@Name='SalesForecastApprovalWorkflow']", nsMgr);
                XmlNode documentApprovalWorkflowTemplateIdSet =
                    documentApprovalWorkflowTemplate.SelectSingleNode("spWf:WorkflowTemplateIdSet", nsMgr);
                string documentApprovalWorkflowTemplateId =
                    documentApprovalWorkflowTemplateIdSet.Attributes["TemplateId"].Value;
                XmlNode runningWorkflow =
                    workflowInfo.SelectSingleNode("//spWf:ActiveWorkflowsData/spWf:Workflows/spWf:Workflow[@TemplateId='" + documentApprovalWorkflowTemplateId + "' and @Status1=2]", nsMgr);
                if (runningWorkflow == null)
                {
                    MessageBox.Show("Workflow isn't running");
                    return false;
                }
                else
                {
                    XmlNode todoNode = workflowWebSvc.GetToDosForItem(ExcelLink.NavigateUri.ToString());
                    XmlNodeList workflowTaskNodes =
                        todoNode.SelectNodes("//z:row", nsMgr);
                    XmlNode workflowTaskNode = null;
                    // Just need to ensure we get the last item in the list and this
                    // isn't efficient but should do the job.
                    //foreach (XmlNode taskRow in workflowTaskNodes)
                    //{
                    //    workflowTaskNode = taskRow;
                    //}
                    if (workflowTaskNodes.Count > 0)
                    {
                        workflowTaskNode = workflowTaskNodes[workflowTaskNodes.Count - 1];
                    }
                    if (workflowTaskNode != null)
                    {
                        int workflowTaskId = int.Parse(workflowTaskNode.Attributes["ows_ID"].Value);
                        XmlSerializer serializer = new XmlSerializer(typeof(WorkflowApprovalData));
                        using (MemoryStream stream = new MemoryStream())
                        {
                            serializer.Serialize(stream, workflowData);
                            stream.Position = 0;
                            XmlDocument workflowParametersDocument = new XmlDocument();
                            workflowParametersDocument.Load(stream);
                            XmlNode alterInfo = workflowWebSvc.AlterToDo(ExcelLink.NavigateUri.ToString(), workflowTaskId, new Guid(runningWorkflow.Attributes["TaskListId"].Value), (XmlNode)workflowParametersDocument.DocumentElement);
                            //MessageBox.Show(alterInfo.OuterXml);
                        }
                    }
                    else
                    {
                        MessageBox.Show("You don't have any active Workflow tasks for this document.");
                        return false;
                    }
                }
                return true;
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
                return false;
            }
        }


    }
}
